package com.wk.jetpackdemo.recyclerview

import android.databinding.DataBindingUtil
import android.databinding.ObservableList
import android.support.v7.util.DiffUtil
import android.support.v7.widget.RecyclerView
import android.text.TextUtils
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import com.wk.jetpackdemo.BR
import com.wk.jetpackdemo.R
import com.wk.jetpackdemo.databinding.ItemPaoBinding
import com.wk.jetpackdemo.entities.Article
import com.wk.jetpackdemo.model.CustomObservableList
import com.wk.jetpackdemo.utils.ImageUtil
import java.util.*
import kotlin.collections.ArrayList

class PaoAdapter(private val list: CustomObservableList<Article>) : RecyclerView.Adapter<BindingViewHolder<ItemPaoBinding>>() {

    companion object {
        private const val TAG = "PaoAdapter"
    }

    private var dataList: ArrayList<Article> = ArrayList()

    init {
        this.dataList.addAll(list)
        list.addOnListChangedCallback(object : ObservableList.OnListChangedCallback<CustomObservableList<Article>>() {
            override fun onChanged(sender: CustomObservableList<Article>?) {
                Log.e(TAG, "onChanged")
//                notifyDataSetChanged()
                refresh(list)
            }

            override fun onItemRangeRemoved(sender: CustomObservableList<Article>?, positionStart: Int, itemCount: Int) {
//                notifyItemRangeRemoved(positionStart, itemCount)
                Log.e(TAG, "onItemRangeRemoved")
                refresh(list)

            }

            override fun onItemRangeMoved(sender: CustomObservableList<Article>?, fromPosition: Int, toPosition: Int, itemCount: Int) {
//                notifyItemMoved(fromPosition, toPosition)
                Log.e(TAG, "onItemRangeMoved")
                refresh(list)
            }

            override fun onItemRangeInserted(sender: CustomObservableList<Article>?, positionStart: Int, itemCount: Int) {
//                notifyItemRangeInserted(positionStart, itemCount)
                Log.e(TAG, "onItemRangeInserted:$positionStart--->$itemCount")
                refresh(list)
            }

            override fun onItemRangeChanged(sender: CustomObservableList<Article>?, positionStart: Int, itemCount: Int) {
//                notifyItemRangeChanged(positionStart, itemCount)
                Log.e(TAG, "onItemRangeChanged")
                refresh(list)
            }

        })
    }

    private inner class Diff : DiffUtil.Callback() {

        private var oldList: ArrayList<Article>? = null
        private var newList: ArrayList<Article>? = null
        fun calculateDiff(oldList: ArrayList<Article>, newList: ArrayList<Article>) {
            this.oldList = oldList
            this.newList = newList
        }

        override fun areItemsTheSame(p0: Int, p1: Int): Boolean {
            val old = oldList?.get(p0)
            val new = newList?.get(p0)
            return old?.id == new?.id
        }

        override fun getOldListSize(): Int {
            return oldList?.size ?: 0
        }

        override fun getNewListSize(): Int {
            return newList?.size ?: 0
        }

        override fun areContentsTheSame(p0: Int, p1: Int): Boolean {
            val old = oldList?.get(p0)
            val new = newList?.get(p0)
            return Objects.equals(old, new)
        }

        override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Article? {
            Log.e(TAG, "getChangePayload:$oldItemPosition    $newItemPosition")
            val old = oldList?.get(oldItemPosition)
            val new = newList?.get(newItemPosition)
            if (old == null || new == null) return new
            return generateDiff(old, new)
        }

        private fun generateDiff(old: Article, new: Article): Article {
            val article = Article()
            if (!Objects.equals(old.title, new.title)) {
                article.title = new.title
            }
            if (!Objects.equals(old.pubDate, new.pubDate)) {
                article.pubDate = new.pubDate
            }
            if (!Objects.equals(old.thumbnail, new.thumbnail)) {
                article.thumbnail = new.thumbnail
            }
            if (!Objects.equals(old.user, new.user)) {
                article.user = new.user
            }
            return article

        }

    }

    private val diffUtil: Diff by lazy {
        Diff()
    }

    fun refresh(list: ArrayList<Article>) {
        diffUtil.calculateDiff(this.dataList, list)
        DiffUtil.calculateDiff(diffUtil).dispatchUpdatesTo(this)
        this.dataList.clear()
        this.dataList.addAll(list)
    }

    override fun onCreateViewHolder(p0: ViewGroup, p1: Int): BindingViewHolder<ItemPaoBinding> {
        return BindingViewHolder(DataBindingUtil.inflate(LayoutInflater.from(p0.context), R.layout.item_pao, p0, false))
    }

    override fun getItemCount(): Int {
        return dataList.size
    }

    override fun onBindViewHolder(p0: BindingViewHolder<ItemPaoBinding>, p1: Int) {
        p0.binding.setVariable(BR.item, dataList[p1])
        p0.binding.executePendingBindings()
        Log.e(TAG, "onBindViewHolder->normal")
    }

    override fun onBindViewHolder(holder: BindingViewHolder<ItemPaoBinding>, position: Int, payloads: MutableList<Any>) {
        Log.e(TAG, "onBindViewHolder->advanced:${payloads.size}")
        if (payloads.size == 0) {
            this.onBindViewHolder(holder, position)
            return
        }
        val any = payloads[0] as? Article ?: return
        Log.e(TAG, "onBindViewHolder->advanced:$any")
        if (!TextUtils.isEmpty(any.pubDate)) {
            holder.binding.about.text = any.pubDate
        }
        if (!TextUtils.isEmpty(any.thumbnail)) {
            ImageUtil.load(any.thumbnail, holder.binding.thumbnail)
        }
        if (!TextUtils.isEmpty(any.title)) {
            holder.binding.desc.text = any.title
        }
        if (any.user != null) {
            ImageUtil.load(any.user?.face, holder.binding.avatar, true)
        }
        if (!TextUtils.isEmpty(any.user?.nickname)) {
            holder.binding.title.text = any.user?.nickname
        }

    }
}
